package com.triones.api.service.third;

import cn.hutool.core.convert.Convert;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.config.PhotonPayConfig;
import com.ruoyi.common.constant.PhpApiPathConstants;
import com.ruoyi.common.constant.PhpOauthConstants;
import com.ruoyi.common.utils.PhpApiSignUtils;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.triones.api.entity.*;
import com.triones.api.entity.bo.*;
import com.triones.api.entity.param.AvailableParams;
import com.triones.api.entity.param.CardBinParams;
import com.triones.api.entity.param.CardDetailParams;
import com.triones.api.entity.param.WalletSingleParams;
import com.triones.api.mapper.CardholderMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.Duration;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * php 接口（调用第三方）业务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PhotonPayServiceImpl implements PhotonPayService {

    private final PhotonPayConfig photonPayConfig;

    private final OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .build();

    @Override
    public List<Map> getCardBin(CardBinParams params) {
        List<Map> list = (List<Map>) sendGet(PhpApiPathConstants.getCardBin,params);
        return list;
    }

    @Override
    public Map addCardholder(CardholderBodyBO bo) {
        return (Map) sendPost(PhpApiPathConstants.addCardholder, bo);
    }

    @Override
    public Map openCard(BankCardBodyBO bo) {
        Map map = (Map) sendPost(PhpApiPathConstants.openCard,bo);
        System.out.println("map = " + map);
        return map;
    }

    @Override
    public Map cardActivate(CardActivateBO bo) {
        return (Map) sendPost(PhpApiPathConstants.activateCard,bo);
    }

    @Override
    public void freezeCard(BankCardFreezeRecordDO dto) {
        sendPost(PhpApiPathConstants.freezeCard,dto);
    }

    @Override
    public String getPhotonPayToken() {
        String photonPayToken = "";
        long tokenTimeToLive = RedisUtils.getTimeToLive(PhpOauthConstants.PHOTON_PAY_TOKEN);
        if (tokenTimeToLive < 10 * 60) {
            this.photonPayGetToken();
        }
        photonPayToken = RedisUtils.getCacheObject(PhpOauthConstants.PHOTON_PAY_TOKEN);
        return photonPayToken;
    }

    @Override
    public Map addRecipient(RecipientBodyBO bo) {
        return (Map) sendPost(PhpApiPathConstants.addRecipient,bo);
    }

    @Override
    public Map updateCard(UpdateCardRequestBodyBO bo) {
        return (Map) sendPost(PhpApiPathConstants.updateCard,bo);
    }

    @Override
    public Map textTxn(SandBoxTransactionRequestBodyBO bo) {
        return (Map) sendPost(PhpApiPathConstants.sandBoxTransaction,bo);
    }

    @Override
    public Map getCardDetail(CardDetailParams params) {
        return (Map) sendGet(PhpApiPathConstants.getCardDetail,params);
    }

    @Override
    public Map walletSingle(WalletSingleParams params) {
        return (Map) sendGet(PhpApiPathConstants.walletSingle,params);
    }

    /**
     * 发送get请求
     * @param apiLink
     * @param param
     * @return
     */
    public Object sendGet(String apiLink,Object param) {
        String contentType = "application/json";
        Request request = new Request.Builder()
            .url(photonPayConfig.getUrl() + apiLink + "?" + PhpApiSignUtils.convertObjectToQueryString(param))
            .get()
            .header("content-type", contentType)
            .header("X-PD-TOKEN", getPhotonPayToken())
            .build();
        log.info("请求url： " + photonPayConfig.getUrl() + apiLink + "?" + PhpApiSignUtils.convertObjectToQueryString(param));
        log.info("请求时间： " + System.currentTimeMillis());
        log.info("请求Headers： " + request.headers());
        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                ObjectMapper objectMapper = new ObjectMapper();
                String responseBody = response.body().string();
                log.info("请求时间: " + System.currentTimeMillis());
                log.info("响应参数 : {}", responseBody);
                Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
                if (responseMap.get("code").equals("0000")) {
                    System.out.println("responseMap.get(data) = " + responseMap.get("data"));
                    return responseMap.get("data");
                }
            } else {
                log.error("Request failed: {}", response.code());
                System.out.println("失败 - 响应参数 ：" + Convert.toStr(response.code()));
                throw new SecurityException("");
            }
        } catch (IOException e) {
            log.error("IOException occurred: ", e);
            throw new SecurityException("");
        }
        throw new SecurityException("repeated requests");
    }

    /**
     * 发送post请求
     * @param apiLink
     * @param obj
     * @return
     */
    public Object sendPost(String apiLink,Object obj) {
        String contentType = "application/json";
        MediaType mediaType = MediaType.parse(contentType);
        //根据实际需要设置请求体内容
        RequestBody body = RequestBody.create(mediaType, PhpApiSignUtils.convertObjectToJson(obj));
        Request request = new Request.Builder()
            .url(photonPayConfig.getUrl() + apiLink)
            .post(body)
            .header("content-type", contentType)
            .header("X-PD-SIGN", PhpApiSignUtils.sign(PhpApiSignUtils.convertObjectToJson(obj),photonPayConfig.getMerchantPrivateKey()))
            .header("X-PD-TOKEN", getPhotonPayToken())
            .build();
        System.out.println("request = " + request);
        log.info("请求url： " + photonPayConfig.getUrl() + apiLink);
        log.info("请求时间： " + System.currentTimeMillis());
        log.info("请求body： " + PhpApiSignUtils.convertObjectToJson(obj));
        log.info("请求Headers： " + request.headers());
        try (Response response = client.newCall(request).execute()) {
            System.out.println("response = " + response);
            if (response.isSuccessful()) {
                ObjectMapper objectMapper = new ObjectMapper();
                String responseBody = response.body().string();
                log.info("请求时间: " + System.currentTimeMillis());
                log.info("响应参数 : {}", responseBody);
                Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
                if (responseMap.get("code").equals("0000")) {
                    return responseMap.get("data");
                } else {
                    throw new SecurityException(Convert.toStr(responseMap.get("msg")));
                }
            } else {
                log.error("Request failed: {}", response.code());
                log.error("Request failed msg: {}", response);
                System.out.println("失败 - 响应参数 ：" + Convert.toStr(response.code()));
                throw new SecurityException("请求出错");
            }
        } catch (IOException e) {
            log.error("IOException occurred: ", e);
            throw new SecurityException("请求异常");
        }
    }


    /**
     * 初始化加载photonPay的token
     */
    public void photonPayGetToken() {
        /**
         * curl --request POST \
         * --url 'https://x-api1.uat.photontech.cc/oauth2/token/accessToken' \
         * --header 'content-type: application/json' \
         * --header 'Authorization: basic YzhCZFY5UGUvZDU2MDA1ZjI0YTZjYWM2YzZjZDE2MDRhNmM0YTZjZDEzNWMxYWM1MQ=='
         */
        String combined = photonPayConfig.getAppid() + "/" + photonPayConfig.getAppsecret();
        String contentType = "application/json";
        String authorization = "basic " + Base64.getEncoder().encodeToString(combined.getBytes());
        System.out.println("authorization = " + authorization);
        MediaType mediaType = MediaType.parse(contentType);
        //根据实际需要设置请求体内容
        RequestBody body = RequestBody.create(mediaType, "{}");
        Request request = new Request.Builder()
            .url(photonPayConfig.getUrl() + PhpApiPathConstants.accessToken)
            .post(body)
            .header("content-type", contentType)
            .header("Authorization", authorization)
            .build();
        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                ObjectMapper objectMapper = new ObjectMapper();
                String responseBody = response.body().string();
                log.info("成功 - 响应参数 : {}", responseBody);
                Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
                if (responseMap.get("code").equals("0000")) {
                    Map<String, Object> dataMap = (Map<String, Object>) responseMap.get("data");
                    RedisUtils.setCacheObject(PhpOauthConstants.PHOTON_PAY_TOKEN, dataMap.get("token"),
                        Duration.ofSeconds((Convert.toLong(dataMap.get("expiresIn")) - System.currentTimeMillis()) / 1000));
                    RedisUtils.setCacheObject(PhpOauthConstants.PHOTON_PAY_REFRESH_TOKEN, dataMap.get("refreshToken"),
                        Duration.ofSeconds((Convert.toLong(dataMap.get("refreshExpiresIn")) - System.currentTimeMillis()) / 1000));
                }
            } else {
                log.error("Request failed: {}", response.code());
                System.out.println("失败 - 响应参数 ：" + Convert.toStr(response.code()));
            }
        } catch (IOException e) {
            log.error("IOException occurred: ", e);
        }
    }
}
